#ifdef __GNUG__
#pragma implementation
#endif

#include "SunBitmap.h"

#include "Class.h"
#include "String.h"
#include "Error.h"
#include "SunWindowSystem.h"
#include "SunWindowPort.h"

#include "pix.h"

//---- SunBitmap ------------------------------------------------------------------

SunBitmap::SunBitmap(Point sz, u_short *im, u_short dep, bool fd) : DevBitmap(sz, dep)
{
	if (dep <= 1)
		depth= 1;
	else if (dep <= 8)
		depth= 8;
	else if (dep <= 32)
		depth= 32;

	if (im) {
		pr= mem_point(sz.x, sz.y, depth, (short*) im);
		pr->pr_data->md_primary= fd ? 1 : 0;
	} else {
		pr= mem_create(size.x, size.y, depth);
	}
}

SunBitmap::SunBitmap(pixrect *npr, bool copy) : DevBitmap(this)
{
	if (npr) {
		if (copy)
			pr= ClonePixrect(npr);
		else
			pr= npr;
		size.x= pr->pr_size.x;
		size.y= pr->pr_size.y;
		depth= pr->pr_depth;
	}
}

SunBitmap::~SunBitmap()
{
	if (pr) {
		pr_destroy(pr);
		pr= 0;
	}
}

DevBitmap *SunBitmap::DevAllocBitmap(const Point &s, u_short d)
{
	return new SunBitmap(s, 0, d);
}

void SunBitmap::SetPixel(u_int x, u_int y, u_long value)
{
	pr_put(pr, x, y, value);
}

u_long SunBitmap::GetPixel(u_int x, u_int y)
{
	return pr_get(pr, x, y);
}

void SunBitmap::SetRow(BitmapInfo *bi, int row, byte *rowdata)
{
	if (bi->bitsperpixel == 1 || bi->bitsperpixel == 8) {
		byte *to= &((byte*)pr->pr_data->md_image)[row*pr->pr_data->md_linebytes];
		MemCpy(to, rowdata, pr->pr_data->md_linebytes);
	} else
		DevBitmap::SetRow(bi, row, rowdata);
}

void SunBitmap::SetData(BitmapInfo *bi, void *data)
{
	if (0 && (bi->rowpad % 2) == 0 && bi->bitsperpixel == 32) {
		if (pr)
			pr_destroy(pr);
		pr= mem_point(size.x, size.y, depth, (short*) data);
		pr->pr_data->md_primary= 1;
	} else
		DevBitmap::SetData(bi, data);
}

void SunBitmap::ReadData(BitmapInfo *bi, IStream &is)
{
	if (bi->rowpad == 2 && (bi->bitsperpixel == 1 || bi->bitsperpixel == 8 || bi->bitsperpixel == 32))
		is.read((byte*)pr->pr_data->md_image, pr->pr_data->md_linebytes * size.y);
	else
		DevBitmap::ReadData(bi, is);
}

void SunBitmap::DevMapColors(DevBitmap *src, u_long *map)
{
	pixrect *spr= ((SunBitmap*)src)->pr;

	if (spr->pr_data->md_linebytes != pr->pr_data->md_linebytes) {
		DevBitmap::DevMapColors(src, map);
		return;
	}

	register u_char *from, *to;
	register int n, l;

	from= (u_char*) spr->pr_data->md_image;
	to= (u_char*) pr->pr_data->md_image;
	l= pr->pr_data->md_linebytes * size.y;
	n= (l+7)/8;

	// courtesy: tom duff
	switch (l % 8) {
	case 0: do {    *to++= (u_char) map[*from++];
	case 7:         *to++= (u_char) map[*from++];
	case 6:         *to++= (u_char) map[*from++];
	case 5:         *to++= (u_char) map[*from++];
	case 4:         *to++= (u_char) map[*from++];
	case 3:         *to++= (u_char) map[*from++];
	case 2:         *to++= (u_char) map[*from++];
	case 1:         *to++= (u_char) map[*from++];
			} while (--n > 0);
	}
}

void SunBitmap::DevBitBlt(int x, int y, int w, int h, BitBltOp op,
				DevBitmap *s, int sx, int sy, u_long val)
{
	pixrect *pr2= 0;
	if (s)
		pr2= ((SunBitmap*)s)->pr;
	switch (op) {
	case eBitCopy:
		pr_rop(pr, x, y, w, h, PIX_SRC|PIX_DONTCLIP, pr2, sx, sy);
		break;
	case eBitOr:
		pr_rop(pr, x, y, w, h, PIX_OR|PIX_DONTCLIP, pr2, sx, sy);
		break;
	case eBitSet:
		pr_rop(pr, x, y, w, h, PIX_SRC|PIX_COLOR((int)val)|PIX_DONTCLIP, 0, sx, sy);
		break;
	}
}

//---- pixrect utilities -------------------------------------------------------

bool NewPixrect(pixrect **prp, Point e, bool exact, bool clear, int depth)
{
	struct pixrect *pr= *prp;

	if (pr == 0 || pr->pr_size.x != e.x || pr->pr_size.y != e.y || depth != pr->pr_depth) {
		if (pr == 0 || pr->pr_size.x < e.x || pr->pr_size.y < e.y || depth != pr->pr_depth || exact) {
			if (pr)
				pr_destroy(pr);
			if ((*prp= pr= mem_create(e.x, e.y, depth)) == 0)
				Error("NewPixrect", "can't allocate pixrect");
			return TRUE;
		}
	}
	if (clear) {
		pr_rop(pr, 0, 0, e.x, e.y, PIX_CLR|PIX_DONTCLIP, 0, 0, 0);
		return TRUE;
	}
	return FALSE;
}

pixrect *ClonePixrect(pixrect *pr)
{
	pixrect *clone= 0;
	if (pr) {
		clone= mem_create(pr->pr_size.x, pr->pr_size.y, pr->pr_depth);
		pr_rop(clone, 0, 0, pr->pr_size.x, pr->pr_size.y, PIX_SRC|PIX_DONTCLIP, pr, 0, 0);
	}
	return clone;
}

pixrect *ScalePixrect(pixrect *pr, int sx, int sy)
{
	SunBitmap *sbm= new SunBitmap(pr);
	SunBitmap *spr= (SunBitmap*) sbm->DevScaleBitmap(Point(sx, sy));
	delete sbm;
	return spr->pr;
}

